import DoubleClickZoom from 'ol/interaction/DoubleClickZoom'
import lineSplit from '@turf/line-split'
import booleanPointInPolygon from '@turf/boolean-point-in-polygon'
import { point as TurfPoint, lineString, polygon as TurfPolygon, featureCollection } from '@turf/helpers'
import lineIntersect from '@turf/line-intersect'
import explode from '@turf/explode'
import buffer from '@turf/buffer'
import difference from '@turf/difference'
import distance from '@turf/distance'

import GeoJSONFormat from 'ol/format/geojson'
import { GEOMETRYTYPE } from '../const'
import { mergeLines, mergeJsonFeatures } from './merge'
const jsonFormat = new GeoJSONFormat()

/**
 * 将feature转为geojson
 * @param {ol.Feature} feature -输入feature
 * @param {string} [dataProjection=EPSG:3857] - 数据投影
 * @param {string} [featureProjection=EPSG:4326] - 要素投影
 * @return {geojson}
 */
export function feature2Geojson (feature, featureProjection = 'EPSG:3857', dataProjection = 'EPSG:4326') {
  const json = jsonFormat.writeFeature(feature, {
    dataProjection: dataProjection,
    featureProjection: featureProjection
  })
  return JSON.parse(json)
}

/**
 * 将feature转为geojson
 * @param {array<ol.Feature>} features -features
 * @param {string} [featureProjection=EPSG:3857] - 要素投影
 * @param {string} [dataProjection=EPSG:4326] - 数据投影
 * @return {geojson}
 */
export function features2Geojson (features, featureProjection = 'EPSG:3857', dataProjection = 'EPSG:4326') {
  const json = jsonFormat.writeFeatures(features, {
    dataProjection: dataProjection,
    featureProjection: featureProjection
  })
  return JSON.parse(json)
}

/**
 * 合并features
 * @param {Array<ol.Feature>} features - 输入features
 * @return {ol.Feature} - 合并结果
 */
export function mergeFeatures (features) {
  const json = features2Geojson(features)
  const jsonFeatures = json.features
  const geomType = jsonFeatures[0].geometry.type.toLowerCase()
  const res = geomType.indexOf('linestring') !== -1 ? mergeLines(jsonFeatures) : mergeJsonFeatures(jsonFeatures)
  const feature = geojson2Features(res)[0]
  feature.set('geometryType', GEOMETRYTYPE[feature.getGeometry().getType().toUpperCase()])
  return feature
}

/**
 * 将json转换为features
 * @param json - 输入JSON
 * @param insr [insr=EPSG:4326] - 输入投影
 * @param {string} [outsr=EPSG:3857] - 输出投影
 * @return {array<ol.Feature>}
 */
export function geojson2Features (json, insr = 'EPSG:4326', outsr = 'EPSG:3857') {
  return jsonFormat.readFeatures(json, {
    dataProjection: insr,
    featureProjection: outsr
  })
}

/**
 * 根据圆心和半径获取圆
 * @param center
 * @param radius
 * @return {*[]}
 */
export function getCircleCoords (center, radius) {
  const getCoordsByAngle = function (center, r, angle) {
    // 转换成弧度
    angle = angle / 180 * Math.PI
    const x = center[0] + Math.cos(angle) * r
    const y = center[1] + Math.sin(angle) * r
    return [x, y]
  }
  let coords = []
  for (let i = 0; i <= 120; i++) {
    const angle = i * 3
    coords.push(getCoordsByAngle(center, radius, angle))
  }
  return coords
}

/**
 * 过滤掉重复点
 * @param {array} coords - 坐标点集合
 */
export function filterDuplicatePoints (coords) {
  let newCoords = []
  const coordsCopy = [...coords]
  for (let i = 0; i < coordsCopy.length; i++) {
    const coord = coordsCopy[i]
    if (i === 0 || coord[0] !== newCoords[newCoords.length - 1][0] || coord[1] !== newCoords[newCoords.length - 1][1]) {
      newCoords.push(coord)
    }
  }
  return newCoords
}

/**
 * 切换双击放大
 * @param map
 * @param state
 */
export function toggleDoubleZoom (map, state = true) {
  const dblClickInteraction = map
    .getInteractions()
    .getArray()
    .find(interaction => {
      return interaction instanceof DoubleClickZoom
    })
  dblClickInteraction.setActive(state)
}

/**
 * 打断线
 * @param {Geojson} polygon - 被打断线
 * @param {Geojson} line - 打断线
 * @return {FeatureCollection} - 打断结果，为多条线
 */
export function lineStringCut (poly, line) {
  let res = {
    'type': 'FeatureCollection',
    'features': []
  }
  if (poly.geometry.type === 'MultiLineString') {
    const coordinates = poly.geometry.coordinates
    for (let i = 0; i < coordinates.length; i++) {
      const _poly = lineString(coordinates[i])
      let _res = lineSplit(_poly, line)
      _res = _res.features.length === 0 ? [_poly] : _res.features
      res.features = res.features.concat(_res)
    }
  } else {
    res = lineSplit(poly, line)
    res = res.features.length === 0 ? poly : res
  }
  res.features.forEach((feat, index) => {
    feat.properties = Object.assign({}, poly.properties)
    feat.properties.id += '-' + index
  })
  return res
}

/**
 * 切割多边形
 * @param {Geojson} polygon - 被切割多边形
 * @param {Geojson} line - 切割线
 * @return {FeatureCollection} - 切割结果，为多个polygon
 */
export function polygonCut (poly, line) {
  let tolerance = 0.001
  let toleranceType = 'kilometers'
  // 1. 条件判断
  if (poly.geometry === void 0 || poly.geometry.type.indexOf('Polygon') === -1) { console.error('传入的必须为polygon') }
  if (line.geometry === void 0 || line.geometry.type.toLowerCase().indexOf('linestring') === -1) { console.error('传入的必须为linestring') }
  if (line.geometry.type === 'LineString') {
    if (booleanPointInPolygon(TurfPoint(line.geometry.coordinates[0]), poly) ||
      booleanPointInPolygon(TurfPoint(line.geometry.coordinates[line.geometry.coordinates.length - 1]), poly)) { console.error('起点和终点必须在多边形之外') }
  }
  // 2. 计算交点，并把线的点合并
  let intersectLine = lineIntersect(line, poly)
  const lineExp = explode(line)
  for (let i = 0; i < lineExp.features.length - 1; i++) {
    intersectLine.features.push(TurfPoint(lineExp.features[i].geometry.coordinates))
  }
  // 3. 计算线的缓冲区
  const lineBuffer = buffer(line, tolerance, {
    units: toleranceType
  })
  // 4. 计算线缓冲和多边形的different，返回"MultiPolygon"，所以将其拆开
  const _body = difference(poly, lineBuffer)
  let pieces = []
  if (_body.geometry.type === 'Polygon') {
    pieces.push(TurfPolygon(_body.geometry.coordinates))
  } else {
    _body.geometry.coordinates.forEach(function (a) { pieces.push(TurfPolygon(a)) })
  }
  // 5. 处理点数据
  for (const p in pieces) {
    const piece = pieces[p]
    for (let c in piece.geometry.coordinates[0]) {
      const coord = piece.geometry.coordinates[0][c]
      const p = TurfPoint(coord)
      for (let lp in intersectLine.features) {
        const lpoint = intersectLine.features[lp]
        if (distance(lpoint, p, toleranceType) <= tolerance * 2) {
          piece.geometry.coordinates[0][c] = lpoint.geometry.coordinates
        }
      }
    }
  }
  // 6. 过滤掉重复点
  for (const p in pieces) {
    const coords = pieces[p].geometry.coordinates[0]
    pieces[p].geometry.coordinates[0] = filterDuplicatePoints(coords)
  }
  // 7. 将属性赋予每一个polygon，并处理id
  pieces.forEach((a, index) => {
    a.properties = Object.assign({}, poly.properties)
    a.properties.id += `-${index}`
    a.properties.geometryType = 'polygon'
  })
  return featureCollection(pieces)
}
